package com.ervanalb.cellradio.server;

import java.io.IOException;
import java.net.InetAddress;

import com.ervanalb.cellradio.client.Informational;
import com.ervanalb.cellradio.shared.ClientState;
import com.ervanalb.cellradio.shared.communicator.Communicator;
import com.ervanalb.cellradio.shared.communicator.ReplyListener;
import com.ervanalb.cellradio.shared.communicator.ResponseListener;
import com.ervanalb.cellradio.shared.communicator.packets.AuthenticatedData;
import com.ervanalb.cellradio.shared.communicator.packets.DisconnectPacketData;
import com.ervanalb.cellradio.shared.communicator.packets.HelloPacketData;
import com.ervanalb.cellradio.shared.communicator.packets.Packet;
import com.ervanalb.cellradio.shared.communicator.packets.PacketData;

/**
 * Represents a connected client on the server side. The server maintains a
 * ClientPresence for every connected client. Provides useful methods for
 * interacting with the client. Not to be confused with ClientState-- this
 * method contains a ClientState among other things, such as methods for
 * interaction.
 * 
 * @author eric
 */
public class ClientPresence {
	public Communicator comm;
	public InetAddress addr;
	public int id;
	public ClientState cs;

	public ClientPresence(Communicator comm, int id, InetAddress addr) {
		this.comm = comm;
		this.addr = addr;
		this.id = id;
		this.cs = new ClientState();
	}

	public Informational<Boolean> tellClient(PacketData pd) throws IOException {
		return tellClient(pd, 0);
	}

	public Informational<Boolean> tellClient(PacketData pd, int replyTo)
			throws IOException {
		Packet p = new Packet(0, id, replyTo, pd, addr);

		Informational<ResponseListener> i = comm.safeSend(p, false);
		if (i != null) // Completely null result means success
			return new Informational<Boolean>(false, "Failed to tell client: "
					+ i.message);

		return new Informational<Boolean>(true);
	}

	public Informational<ResponseListener> queryClient(PacketData pd)
			throws IOException {
		Packet p = new Packet(0, id, 0, pd, addr);
		Informational<ResponseListener> i = comm.safeSend(p, true);
		if (i.result == null)
			i.message = "Failed to query client: " + i.message;
		return i;
	}

	public Informational<Packet> queryClientBlock(PacketData pd, long timeout)
			throws IOException {

		Packet p = new Packet(0, id, 0, pd, addr);
		Informational<ResponseListener> i = comm.safeSend(p, true);

		ReplyListener rl = i.result;
		if (rl == null) {
			return new Informational<Packet>("Failed to query client: "
					+ i.message);
		}

		Packet response = rl.getReply(timeout);
		if (response == null)
			return new Informational<Packet>(
					"Timed out waiting for reply from client.");
		return new Informational<Packet>(response);
	}

	public Informational<Boolean> sendHello() throws IOException {
		PacketData pd = new HelloPacketData().pack();
		Informational<Boolean> i = tellClient(pd);
		if (!i.result)
			return new Informational<Boolean>("send hello: " + i.message);
		return i;

	}

	public void sendDisconnect() throws IOException {
		tellClient(new DisconnectPacketData().pack());
	}

	public void cutoff() {
		comm.finish();
	}

	public Informational<Boolean> sendAuthenticated(byte success, int replyTo)
			throws IOException {
		return tellClient(new AuthenticatedData(success).pack(), replyTo);
	}

	public String toString() {
		String s = cs.username.get();
		if (s != null) {
			return s;
		} else {
			return "" + id;
		}
	}
}
